package com.intersult.nutils.net;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.security.MessageDigest;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;

public class InstallCert {
	private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
	
	public static void main(String[] args) throws Exception {
		if (args.length < 1) {
			System.out.println("Usage: install-cert <host>[:port] [passphrase]");
			System.err.println("    by Dieter Kaeppel");
			return;
		}
		InetSocketAddress socketAddress = getSocketAddress(args[0]);
		String key = args.length == 1 ? "changeit" : args[1];
		install(socketAddress, key);
	}

	public static InetSocketAddress getSocketAddress(String address) {
		String[] strings = address.split(":");
		return new InetSocketAddress(strings[0], strings.length == 1 ? 443 : Integer.parseInt(strings[1]));
	}
	
	public static void install(InetSocketAddress socketAddress, String key) throws Exception {
		System.out.println("JVM installation " + System.getProperty("java.home"));
		System.out.println("Loading keystore");

		SSL session = new SSL(key);

		System.out.println("Connecting to " + socketAddress);
		SSLSocket socket = session.createSocket(socketAddress);
		socket.setSoTimeout(30000);
		try {
			System.out.println("Testing SSL");
			socket.startHandshake();
			socket.close();
			System.out.println();
			System.out.println("Certificate is already trusted");
			return;
		} catch (SSLException exception) {
			System.out.println(exception.getMessage());
		}

		X509Certificate[] certificates = session.getCertificates();
		if (certificates == null) {
			System.out.println("Could not obtain server certificate chain");
			return;
		}

		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		System.out.println();
		System.out.println("Server sent " + certificates.length + " certificate(s):");
		System.out.println();
		MessageDigest sha1 = MessageDigest.getInstance("SHA1");
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		for (int i = 0; i < certificates.length; i++) {
			X509Certificate certificate = certificates[i];
			System.out.println(" " + (i + 1) + " Subject " + certificate.getSubjectDN());
			System.out.println("   Issuer  " + certificate.getIssuerDN());
			sha1.update(certificate.getEncoded());
			System.out.println("   SHA1    " + toHexString(sha1.digest()));
			md5.update(certificate.getEncoded());
			System.out.println("   MD5     " + toHexString(md5.digest()));
			System.out.println();
		}

		System.out.println("Add certificate to keystore or 'q' to quit: [1]");
		String input = reader.readLine().trim();
		int index;
		try {
			index = (input.length() == 0) ? 0 : Integer.parseInt(input) - 1;
		} catch (NumberFormatException e) {
			System.out.println("KeyStore not changed");
			return;
		}

		X509Certificate cert = certificates[index];
		String alias = socketAddress.getHostName() + "-" + (index + 1);
		session.getKeyStore().setCertificateEntry(alias, cert);
		session.writeKeyStore();

		System.out.println();
		System.out.println(cert);
		System.out.println();
		System.out.println("Added certificate to keystore using alias '" + alias + "'");
	}

	private static String toHexString(byte[] bytes) {
		StringBuilder buffer = new StringBuilder(bytes.length * 3);
		for (int b : bytes) {
			b &= 0xff;
			buffer.append(HEXDIGITS[b >> 4]);
			buffer.append(HEXDIGITS[b & 15]);
			buffer.append(' ');
		}
		return buffer.toString();
	}
}